Skip to content

feat: Sign In progress indicator and timeout COMPASS-10996 - #8391

Open
esvm wants to merge 8 commits into
mainfrom
COMPASS-10996
Open

feat: Sign In progress indicator and timeout COMPASS-10996#8391
esvm wants to merge 8 commits into
mainfrom
COMPASS-10996

Conversation

@esvm

@esvm esvm commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Description

  1. Implement a progress indicator while user is signing in. Hides the action buttons in the meantime.
  2. Times out the Sign In attempt after 2 minutes
    a. Shows a Toast with a custom message
    b. Re-render the action buttons
  3. Tracks the timeout event
  4. Tracks the user aborted (canceled) event
  5. Adds attempt and previousOutcome to the Atlas Sign In Started event so we can track wether the current attempt is a retry or not
Screen.Recording.2026-08-21.at.13.07.53.mov

Checklist

  • New tests and/or benchmarks are included
  • Documentation is changed or added
  • If this change updates the UI, screenshots/videos are added and a design review is requested
  • If this change could impact the load on the MongoDB cluster, please describe the expected and worst case impact
  • I have signed the MongoDB Contributor License Agreement (https://www.mongodb.com/legal/contributor-agreement)

Motivation and Context

  • Bugfix
  • New feature
  • Dependency update
  • Misc

Open Questions

Dependents

Types of changes

  • Backport Needed
  • Patch (non-breaking change which fixes an issue)
  • Minor (non-breaking change which adds functionality)
  • Major (fix or feature that would cause existing functionality to change)

@esvm esvm self-assigned this Aug 21, 2026
Copilot AI lite review requested due to automatic review settings August 21, 2026 14:34
@esvm esvm added the feature flagged PRs labeled with this label will not be included in the release notes of the next release label Aug 21, 2026
@esvm esvm changed the title Compass 10996 feat: Sign In progress indicator and timeout COMPASS-10996 Aug 21, 2026
@github-actions github-actions Bot added the feat label Aug 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the Atlas sign-in flow robustness and observability by adding explicit “in progress” UI state handling, a 2-minute timeout with user feedback, and richer telemetry around retries/outcomes. Overall direction looks solid, but there are a couple of issues to address around event-contract clarity and attempt resource cleanup.

Changes:

  • Adds a sign-in “in progress” state to the assistant tool approval UI (hide actions + show running state).
  • Implements a 2-minute sign-in timeout with toast feedback and telemetry for timeout/cancel events.
  • Extends Atlas Sign In Started telemetry with attempt and previousOutcome to track retries.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/compass-telemetry/src/telemetry-events.ts Extends Atlas sign-in telemetry schema and adds new cancel/timeout event types.
packages/compass-assistant/src/components/atlas-tool-call-message.tsx Updates assistant tool-call UI to reflect sign-in progress and handle timeout results.
packages/compass-assistant/src/components/atlas-tool-call-message.spec.tsx Adds coverage for “sign-in in progress” UI behavior.
packages/atlas-service/src/store/atlas-signin-store-context.tsx Exposes useIsAtlasSignInInProgress and updates signIn() return type to include outcomes.
packages/atlas-service/src/store/atlas-signin-store-context.spec.tsx Adds tests for the new useIsAtlasSignInInProgress selector.
packages/atlas-service/src/store/atlas-signin-reducer.ts Implements timeout/cancel outcomes, retry tracking fields, and new timeout action + telemetry.
packages/atlas-service/src/store/atlas-signin-reducer.spec.ts Adds test coverage for timeout behavior and retry outcome tracking.
packages/atlas-service/src/provider.tsx Re-exports the new useIsAtlasSignInInProgress hook.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/compass-telemetry/src/telemetry-events.ts
Comment thread packages/atlas-service/src/store/atlas-signin-reducer.ts
@esvm
esvm marked this pull request as ready for review August 21, 2026 15:12
@esvm
esvm requested a review from a team as a code owner August 21, 2026 15:12
Comment thread packages/compass-assistant/src/components/atlas-tool-call-message.tsx Outdated
Comment thread packages/atlas-service/src/store/atlas-signin-reducer.ts Outdated
Comment on lines +344 to +346
attempt.timeoutId = setTimeout(() => {
dispatch(timeoutSignIn(attempt.id, entrypoint));
}, SIGN_IN_TIMEOUT_MS);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's confusing that while we have a method that should contain all attempt creation logic it starts to spill out of it, can we revisit this?

I would also maybe suggest to look at the startAttempt once more and consider if more of the logic here that handles cancellation / timeouts can be moved directly to the sign in handling action: both timeouting or cancelling throw a clear error that can be handled (and is already sort of handled) inside the sign in flow

@esvm esvm Aug 25, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I follow what you mean here. The timeout and cancel functions need to exist as they'd be called when something happens in the background. However they're doing a few things today (clearing the timeout, clearing the AttemptStateMap, aborting, dispatching their event and tracking their telemetry event).

I could update the signIn catch do something like:

catch (err) {
      clearTimeout(getAttempt(currentAttemptId).timeoutId);
      AttemptStateMap.delete(currentAttemptId);

      if (!signal.aborted) {
        openToast('atlas-sign-in-error', {
          variant: 'important',
          title: 'Sign in failed',
          description: (err as Error).message,
        });
        dispatch({
          type: AtlasSignInActions.Error,
          error: (err as Error).message,
        });
      }
      
      reject(err);
}

Then both the timeoutSignIn and cancelSignIn would simply do something like

export const cancelSignIn = (reason?: any): AtlasSignInThunkAction<void> => {
  return (dispatch, getState, { track }) => {
    if (getState().currentAttemptId === null) {
      return;
    }
    getAttempt(getState().currentAttemptId).controller.abort(reason ?? 'Sign in canceled');
    dispatch({ type: AtlasSignInActions.Cancel });
    track('Atlas Sign In Canceled', {});
  };
};

Is that what you meant or was it something else?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for not being more detailed there, sometimes hard for me to measure into how much details to go into. What you have here in the suggested refactor is going into the right direction, yeah. What I'm suggesting is to take it even further and package timeout (and more of the cancel handling) completely inside the sign in (we need cancel to be separate because it can be triggered from outside, timeout is completely encapsulated to the flow). In pseudocode something close to this:

function signInAction() {
  try {
    dispatch('SignInStart')
    await Promise.race([
      doSignIn(),
      new Promise((_, reject) => {
        setTimeout(() => { attempt.controller.abort(new TimeoutError()); }, TIMEOUT_MS) 
      })
    ])
  } catch (err) {
    if (attempt.controller.signal.aborted) {
      if (attempt.controller.signal.reason === TimeoutError) {
        // do the timeout handling
        dispatch('SignInTimeout')
      } else {
        // do the cancelled handling
        dispatch('SignInCancel');
      }
    } else {
      // do the other error types handling
      dispatch('SignInError')
    }
  }
}

function cancelAction(reason) {
  return (dispatch, getState) {
    getAttempt(getState().attemptId)?.controller.abort(reason);
  }
}

I think that way you have as much of the sign in logic readable and understandable inside one method without the need of jumping through multiple actions to figure out what's going on. There's also a lot of similarities between how you handle timeout and generic cancel that this allows you to resolve clearly.

I'm okay if we want to do this particular reshuffling a bit later down the road (if this makes sense to you), but I think it will make this reducer easier to work with long term


describe('signOut', function () {
let openToastStub: Sinon.SinonStub;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider if we need all these tests here. in general we're trying to follow the redux testing guidelines and avoid testing the redux internals as much as possible - preferring integrations tests with the UI. see https://redux.js.org/usage/writing-tests#guiding-principles

return getAttempt(currentAttemptId).promise;
return toSignInAttemptResult(
getAttempt(currentAttemptId).promise,
getState

@paula-stacho paula-stacho Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need a fresh getState or can we just use the one obtained at the top of this fn? do we expect it to change and if yes, could this create some inconsistencies in the behaviour?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do not, good catch!

entrypoint,
attempt: getState().attemptNumber,
previousOutcome: isRelevantPreviousState(getState())
? (getState().state as 'error' | 'canceled' | 'timed-out')

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we avoid the typecasting here? plus the same question on getState() use here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I can remove the isRelevantPreviousState function

userInfo = await atlasAuthService.signIn({
signal,
});
track('Atlas Sign In Prompt Shown', {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, this is kinda weird now (or maybe I don't understand what this event is about): this will fire on every successful sign in attempt whereas my understanding is that this should fire instead when the tool card suggesting user to sign in is being displayed first which I think should be either near the code that triggers the tool call (if there is such a thing) or in the rendering method, just using the effect hooks correctly (meaning a clear component that shows sign in state once that can have a clear "onMount" effect setup)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm I thought this part of the code was only triggered when the login page was shown but possibly I'm mistaken (?)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are calling track inside the signIn action which is triggered when user saw the tool card and decided to proceed with sign in and clicked the sign in button, but (as far as I understand from the event description) this event should be triggered when user just saw the tool card, before they decided to proceed:

This event is fired when the user is shown a prompt inviting them to sign in

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah that's right... if the user do not proceed then the event wouldn't be tracked. Will fix it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat feature flagged PRs labeled with this label will not be included in the release notes of the next release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants